
package tman.simulator.core;

import java.io.IOException;
import java.util.HashMap;

import org.apache.log4j.PropertyConfigurator;

import se.sics.kompics.ChannelFilter;
import se.sics.kompics.Component;
import se.sics.kompics.ComponentDefinition;
import se.sics.kompics.Kompics;
import se.sics.kompics.address.Address;
import se.sics.kompics.network.Message;
import se.sics.kompics.network.Network;
import se.sics.kompics.network.NetworkConfiguration;
import se.sics.kompics.network.model.king.KingLatencyMap;
import se.sics.kompics.p2p.bootstrap.BootstrapConfiguration;
import se.sics.kompics.p2p.bootstrap.server.BootstrapServer;
import se.sics.kompics.p2p.bootstrap.server.BootstrapServerInit;
//import se.sics.kompics.p2p.experiment.cyclon.CyclonExperiment;
//import se.sics.kompics.p2p.experiment.cyclon.CyclonSimulator;
//import se.sics.kompics.p2p.experiment.cyclon.CyclonSimulatorInit;
import se.sics.kompics.p2p.experiment.dsl.SimulationScenario;
//import se.sics.kompics.p2p.monitor.cyclon.server.CyclonMonitorConfiguration;
//import se.sics.kompics.p2p.monitor.cyclon.server.CyclonMonitorServer;
//import se.sics.kompics.p2p.monitor.cyclon.server.CyclonMonitorServerInit;
import kompics.P2pOrchestrator;
import kompics.P2pOrchestratorInit;
import common.configuration.AggregationConfiguration;
import common.configuration.ControlConfiguration;
import common.configuration.CyclonConfiguration;
import common.configuration.GLiveConfiguration;
import common.configuration.Global;
import common.configuration.MonitorConfiguration;
import common.configuration.TManConfiguration;
import se.sics.kompics.timer.Timer;
import se.sics.kompics.web.Web;
import se.sics.kompics.web.WebRequest;
import kompics.JettyWebServer;
import kompics.JettyWebServerConfiguration;
import kompics.JettyWebServerInit;
import Monitor.*;
import common.network.model.SimplisticModel;
import common.simulation.SimulatorInit;
import common.simulation.SimulatorPort;
import control.ControlServer;
import control.ControlServerInit;

/**
* The <code>CyclonExecutionMain</code> class.
*
* @author Cosmin Arad <cosmin@sics.se>
* @version $Id$
*/
public final class TManExecutionMain extends ComponentDefinition {
static {
PropertyConfigurator.configureAndWatch("log4j.properties");
}
private static SimulationScenario scenario = SimulationScenario.load(System
.getProperty("scenario"));

public static void main(String[] args) {

if(args != null)
{
	setGlobals(args, 4);
}
else
{
	setGlobals(parseProperties(), 4);
}

Kompics.createAndStart(TManExecutionMain.class, 1);

}

public TManExecutionMain() throws InterruptedException, IOException {
P2pOrchestrator.setSimulationPortType(SimulatorPort.class);
// create
Component p2pOrchestrator = create(P2pOrchestrator.class);
Component jettyWebServer = create(JettyWebServer.class);
Component bootstrapServer = create(BootstrapServer.class);
Component monitorServer = create(TManMonitorServer.class);
Component cyclonSimulator = create(TManSimulator.class);
Component controlServer = create(ControlServer.class);

// loading component configurations
final BootstrapConfiguration bootConfiguration = BootstrapConfiguration.load(System.getProperty("bootstrap.configuration"));
final MonitorConfiguration monitorConfiguration = MonitorConfiguration.load(System.getProperty("cyclon.monitor.configuration"));
final CyclonConfiguration cyclonConfiguration = CyclonConfiguration.load(System.getProperty("cyclon.configuration"));
final TManConfiguration applicationConfiguration = TManConfiguration.load(System.getProperty("tman.configuration"));
final GLiveConfiguration gliveConfiguration = GLiveConfiguration.load(System.getProperty("glive.configuration"));
final AggregationConfiguration aggregationConfiguration = AggregationConfiguration.load(System.getProperty("aggregation.configuration"));
final JettyWebServerConfiguration webConfiguration = JettyWebServerConfiguration.load(System.getProperty("jetty.web.configuration"));
final NetworkConfiguration networkConfiguration = NetworkConfiguration.load(System.getProperty("network.configuration"));
final ControlConfiguration controlConfiguration = ControlConfiguration.load(System.getProperty("control.configuration"));

System.out.println("For web access please go to " + "http://"
+ webConfiguration.getIp().getHostAddress() + ":"
+ webConfiguration.getPort() + "/");
Thread.sleep(2000);

trigger(new P2pOrchestratorInit(scenario, new KingLatencyMap()), p2pOrchestrator.getControl());
//trigger(new P2pOrchestratorInit(scenario, new SimplisticModel()), p2pOrchestrator.getControl());
trigger(new JettyWebServerInit(webConfiguration), jettyWebServer.getControl());
trigger(new BootstrapServerInit(bootConfiguration), bootstrapServer.getControl());
trigger(new TManMonitorServerInit(monitorConfiguration), monitorServer.getControl());
trigger(new ControlServerInit(controlConfiguration), controlServer.getControl());
//trigger(new SimulatorInit(bootConfiguration, monitorConfiguration, cyclonConfiguration, networkConfiguration.getAddress()), cyclonSimulator.getControl());
trigger(new SimulatorInit(bootConfiguration, cyclonConfiguration, applicationConfiguration, gliveConfiguration, aggregationConfiguration, monitorConfiguration, networkConfiguration.getAddress()), cyclonSimulator.getControl());
final class MessageDestinationFilter extends
ChannelFilter<Message, Address> {
public MessageDestinationFilter(Address address) {
super(Message.class, address, true);
}

public Address getValue(Message event) {
return event.getDestination();
}
}
final class WebRequestDestinationFilter extends
ChannelFilter<WebRequest, Integer> {
public WebRequestDestinationFilter(Integer destination) {
super(WebRequest.class, destination, false);
}

public Integer getValue(WebRequest event) {
return event.getDestination();
}
}

connect(bootstrapServer.getNegative(Network.class), p2pOrchestrator.getPositive(Network.class), new MessageDestinationFilter(
	                                bootConfiguration.getBootstrapServerAddress()));
	                connect(bootstrapServer.getNegative(Timer.class), p2pOrchestrator
	                                .getPositive(Timer.class));
	                connect(bootstrapServer.getPositive(Web.class), jettyWebServer
	                                .getNegative(Web.class), new WebRequestDestinationFilter(
	                                bootConfiguration.getBootstrapServerAddress().getId()));
	
	                connect(monitorServer.getNegative(Network.class), p2pOrchestrator
	                                .getPositive(Network.class), new MessageDestinationFilter(
	                                monitorConfiguration.getMonitorServerAddress()));
	                connect(monitorServer.getNegative(Timer.class), p2pOrchestrator
	                                .getPositive(Timer.class));
	                connect(monitorServer.getPositive(Web.class), jettyWebServer
	                                .getNegative(Web.class), new WebRequestDestinationFilter(
	                                monitorConfiguration.getMonitorServerAddress().getId()));
	                
	                connect(controlServer.getNegative(Network.class), p2pOrchestrator
                            .getPositive(Network.class), new MessageDestinationFilter(
                            controlConfiguration.getControlServerAddress()));
	                connect(controlServer.getNegative(Timer.class), p2pOrchestrator
                            .getPositive(Timer.class));
	                connect(controlServer.getPositive(Web.class), jettyWebServer
                            .getNegative(Web.class), new WebRequestDestinationFilter(
                            controlConfiguration.getControlServerAddress().getId()));
	                connect(controlServer.getPositive(SimulatorPort.class), cyclonSimulator
	                		.getNegative(SimulatorPort.class));
	
	                connect(cyclonSimulator.getNegative(Network.class), p2pOrchestrator
	                                .getPositive(Network.class));
	                connect(cyclonSimulator.getNegative(Timer.class), p2pOrchestrator
	                                .getPositive(Timer.class));
	                connect(cyclonSimulator.getPositive(Web.class), jettyWebServer
	                                .getNegative(Web.class));
	                connect(cyclonSimulator.getNegative(SimulatorPort.class),
	                                p2pOrchestrator.getPositive(SimulatorPort.class));
	        }

private static void setGlobals(String[] args, int seed)
{
	Global.odDistr = new HashMap<Integer, Integer>();
	    Global.seed = seed; //Set seed for all RNGs used throughout the project
	    
	    Global.id = Integer.parseInt(args[0]);
	    Global.sl = Integer.parseInt(args[1]);
	    Global.vs = Integer.parseInt(args[2]);
	    Global.tsl = Integer.parseInt(args[3]);
	    Global.tvs = Integer.parseInt(args[4]);
	    Global.srcOD = Integer.parseInt(args[5]);
	    Global.r = Integer.parseInt(args[args.length-1]);
	    
	    for(int i=6; i<args.length-1; i++)
	    {
	    	String[] temp = args[i].split(":");
	    	Global.odDistr.put(Integer.parseInt(temp[0]), Integer.parseInt(temp[1]));
	    }
}

private static String[] parseProperties()
{
	String[] splits = System.getProperty("od").split(";");
	String[] properties = new String[splits.length + 7];
	properties[0] = System.getProperty("id");
	properties[1] = System.getProperty("sl");
	properties[2] = System.getProperty("vs");
	properties[3] = System.getProperty("tsl");
	properties[4] = System.getProperty("tvs");
	properties[5] = System.getProperty("srcOD");
	properties[properties.length-1]= System.getProperty("r");
	for(int i=0; i<splits.length; i++)
	{
		properties[i+6] = splits[i];
	}
	
	return properties;
}
	}